"""
需要先安装:pip3 install aiohttp
aiohttp 基于 asyncio
"""
import os
from datetime import date

import aiohttp
import asyncio

import pytest

import time


async def fetch(session, url):
    print("发送请求:", url)
    async with session.get(url, verify_ssl=False) as response:
        content = await response.content.read()
        code_path = os.path.abspath(__file__)
        file_name = url.rsplit('_')[-1]
        with open(os.path.join(code_path, "files", file_name), mode='wb') as file_object:
            file_object.write(content)


async def download(session, url):
    print("发送请求:", url)
    await asyncio.sleep(3)
    print("{}下载完成".format(url))
    return time.strftime('%Y-%m-%d %H:%M:%S')


def timeit(func):
    """
    计时装饰器，用于统计函数执行时间
    """

    async def wrapper(*args, **kwargs):
        start_time = time.time()
        result = await func(*args, **kwargs)
        end_time = time.time()
        print(f"执行函数 {func.__name__} 耗时：{end_time - start_time} 秒")
        return result

    return wrapper


@timeit
async def main():
    print("main")
    async with aiohttp.ClientSession() as session:
        url_list = [
            "https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90 0 autohomecarchsEe12AXQ6AOOH AAFOCMS8nzU621.jpg",
            "https://www2.autoimg.cn/newsdfs/g30/M01/3c/E2/120x900 autohomecar,chccsV2BBIcAUntfAADiJFd6800429.jpg",
            "https://www3.autoimg.cn/newsdfs/g26/M0B/3c/65/120x90 0 autohomecarCheCP12BFCMAIO83AAGG7VKOSGY193 .jpg"
        ]
        tasks = [asyncio.create_task(download(session, url),name=None) for url in url_list]  # 和线程类似，也可以自定义名称
        # await不能直接等待列表
        done, pending = await asyncio.wait(tasks, timeout=20) # 在设置的timeout=20内未未完成的，会写入pending的集合
        print(done)
        print(pending)
        for d in done:
            print(d.result())


'''
Task，集体await, 是交错进行；
Async函数 await是顺序进行。
-->必须包一层Task
时间结果，有点像线程的start join, start join顺序进行 与 start start  join join的区别
'''


@timeit
async def main2():
    print("main")
    async with aiohttp.ClientSession() as session:
        url_list = [
            "https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90 0 autohomecarchsEe12AXQ6AOOH AAFOCMS8nzU621.jpg",
            "https://www2.autoimg.cn/newsdfs/g30/M01/3c/E2/120x900 autohomecar,chccsV2BBIcAUntfAADiJFd6800429.jpg",
            "https://www3.autoimg.cn/newsdfs/g26/M0B/3c/65/120x90 0 autohomecarCheCP12BFCMAIO83AAGG7VKOSGY193 .jpg"
        ]
        result = [await download(session, url) for url in url_list]
        print(result)
        for r in result:
            print(r)


@timeit
async def main3():
    print("main")
    async with aiohttp.ClientSession() as session:
        url_list = [
            "https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90 0 autohomecarchsEe12AXQ6AOOH AAFOCMS8nzU621.jpg",
            "https://www2.autoimg.cn/newsdfs/g30/M01/3c/E2/120x900 autohomecar,chccsV2BBIcAUntfAADiJFd6800429.jpg",
            "https://www3.autoimg.cn/newsdfs/g26/M0B/3c/65/120x90 0 autohomecarCheCP12BFCMAIO83AAGG7VKOSGY193 .jpg"
        ]
        # result = [await download(session, url) for url in url_list] # 用task套一层，用闭包套一层也行,实质是把要wait的对象延后
        tasks = [lambda url=url: download(session, url) for url in url_list]

        """
                wait的使用：
                在内部wait()
                使用一个set集合保存它创建的Task实例：
                1.因为set集合是无序的所以这也就是我们的任务不是顺序执行的原因。
                2.wait的返回值是一个元组，包括两个集合，分别表示已完成和未完成的任务。
                3. 任务可以取消：task.cancel()
                gather的使用：
                1.gather的作用和wait类似，但不同的是：
                2.gather任务无法取消。
                3.返回值是一个结果列表。
                可以按照传入参数的
                顺序，顺序输出。
        """

        done, pending = await asyncio.wait([task() for task in tasks])
        for d in done:
            print(d.result())
        batch_results = await asyncio.gather(*[task() for task in tasks])
        print(batch_results)
        for r in batch_results:
            print(r)


# asyncio_run 直接用 普通同步函数
def test_asyncio_run_direct():
    start_time = time.time()
    url_list = [
        "https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90 0 autohomecarchsEe12AXQ6AOOH AAFOCMS8nzU621.jpg",
        "https://www2.autoimg.cn/newsdfs/g30/M01/3c/E2/120x900 autohomecar,chccsV2BBIcAUntfAADiJFd6800429.jpg",
        "https://www3.autoimg.cn/newsdfs/g26/M0B/3c/65/120x90 0 autohomecarCheCP12BFCMAIO83AAGG7VKOSGY193 .jpg"
    ]
    result = [download(session=None, url=url) for url in url_list]
    done, pending = asyncio.run(asyncio.wait(result))
    print(done)
    print(pending)
    for d in done:
        print(d.result())
    end_time = time.time()
    print(f"执行函数 test_asyncio_run_direct 耗时：{end_time - start_time} 秒")


if __name__ == '__main__':
        print("begin")
        asyncio.run(main3())  # run的对象，是asyncio.wait对象包一层函数；这样保证了loop先有，再彺上添加task对象
        # test_asyncio_run_direct()

"""
asyncio.run(main())
等价于<=>
loop=asyncio.get_event_1oop()   
1oop.run_unti1_complete(asyncio.wait(tasks))
"""